package com.isyscore.iios.appdemo.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.isyscore.boot.login.LoginUserManager;
import com.isyscore.boot.login.dto.ApiRequest;
import com.isyscore.iios.appdemo.dto.DeviceDTO;
import com.isyscore.iios.appdemo.service.DeviceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Map;

import static com.isyscore.iios.appdemo.constant.OpenApi.DEVICE_LIST_API;

/**
 * 设备服务实现
 *
 * @author author
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private final LoginUserManager userManager;

    @Value("${app.appCode}")
    private String appCode;
    @Value("${mqtt.broker}")
    private String mqttService;
    @Value("${isc.dmc}")
    private String dmcService;

    @Override
    public IPage<DeviceDTO> page(Map<String, Object[]> queryParams) throws Exception {
        //请求URL构建
        UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(dmcService + DEVICE_LIST_API);
        queryParams.forEach(builder::queryParam);
        String url = builder.build().toUri().toString();

        /**
         * 跨服务调用需要在header中设置token。
         * 获得token的前提是在application.yml中正确配置如下参数
         * login.appCode
         * login.appSecret
         * login.permissionUrl
         */
        HttpHeaders headers = new HttpHeaders();
        String token = ApiRequest.getInstance().refreshToken();
        headers.set("token", token);
        HttpEntity<String> entity = new HttpEntity<>(null, headers);

        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            JSONObject jsonObject = JSONUtil.parseObj(response.getBody());
            Page page = jsonObject.getJSONObject("data").toBean(Page.class);
            page.setRecords(jsonObject.getJSONObject("data").getJSONArray("records").toList(DeviceDTO.class));
            return page;
        } else {
            throw new Exception("数据请求失败");
        }
    }

    @Override
    public void subDeviceData(String groupId, String appId, String pk, String devId, String username, String password) throws Exception {
        //获取当前登录人的租户ID
        String tenantId = userManager.getCurrentTenantId();
        //属性上报topic nup/{tenantId}/{groupId}/attr/{appId}/{pk}/{devId}
        String topic = String.format("nup/%s/%s/attr/%s/%s/%s", tenantId, groupId, appId, pk, devId);

        //客户端ID,当前APP的名字+随机值
        String clientId = appCode + RandomUtil.randomNumber();

        MemoryPersistence persistence = new MemoryPersistence();
        try {
            MqttClient client = new MqttClient(mqttService, clientId, persistence);

            // MQTT 连接选项
            MqttConnectOptions connOpts = new MqttConnectOptions();
            //这里的填写的用户名密码，需要具备该topic的订阅权限，否则订阅会失败
            connOpts.setUserName(username);
            connOpts.setPassword(password.toCharArray());
            connOpts.setCleanSession(true);

            // 设置回调
            client.setCallback(new MqttCallback() {
                public void connectionLost(Throwable cause) {
                    // 连接丢失后，一般在这里面进行重连
                    log.info("连接断开，可以做重连");
                }

                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    // subscribe后得到的消息会执行到这里面
                    log.info("topic:{},接收消息内容:{}", topic, new String(message.getPayload()));
                }

                public void deliveryComplete(IMqttDeliveryToken token) {
                }
            });
            // 建立连接
            log.info("Connecting to broker: " + mqttService);
            client.connect(connOpts);
            log.info("Connected");
            // 订阅
            client.subscribe(topic, 0);

        } catch (MqttException me) {
            log.info("reason " + me.getReasonCode());
            log.info("msg " + me.getMessage());
            log.info("loc " + me.getLocalizedMessage());
            log.info("cause " + me.getCause());
            log.info("excep " + me);
            throw new Exception("订阅失败");
        }
    }
}
